import {FileUtil} from "../utils/FileUtil";
import path from "path";
import {ProjectClass} from "./ProjectClass";
import {
  ColorSeries,
  ProjectInfo,
  ProjectScanOptions,
  ProjectScanResult,
  ProjectSimpleInfo,
  ProjectSimpleTree
} from "../types";
import {UNKNOWN_PROJECT_TYPE} from "../constant";
import {globalConfig} from "../config";
import {JsonUtil} from "../utils/JsonUtil";
import {ColorUtil} from "../utils/ColorUtil";

/**
 * 项目扫描器
 */
export class ProjectScanner {

  // 简单信息缓存
  private static simpleMap = new Map<string, ProjectSimpleInfo>();
  // 详细信息缓存
  private static detailMap = new Map<string, ProjectInfo>();

  /**
   * 扫描项目
   * @param targetDir 目标目录
   * @param options 扫描选项
   * @returns 扫描结果
   */
  public static async scanProject(targetDir: string, options: ProjectScanOptions): Promise<ProjectScanResult> {
    // 每次都清空缓存，缓存主要用于获取详情
    this.simpleMap.clear();
    // 查找所有可能的项目 - 使用用户指定的扫描深度和排除目录
    const projectPaths = await this.findProjectPaths(targetDir, options);

    // 扫描每个项目的详细信息
    const projectList: ProjectSimpleInfo[] = [];

    for (const projectPath of projectPaths) {
      const projectInfo = await this.getProjectSimpleInfo(projectPath);
      if (projectInfo) {
        // 存储缓存
        this.simpleMap.set(projectInfo.path, projectInfo);
        projectList.push(projectInfo);
      }
    }

    // 建立项目之间的关系
    const projectTree = this.buildProjectTree(projectList);

    // 整合扫描结果
    return {
      rootPath: targetDir,
      projects: projectTree,
      timestamp: Date.now(),
      scanOptions: options
    };
  }

  /**
   * 查找所有可能的项目路径
   * @param rootPath 根目录路径
   * @param options 扫描选项
   * @returns 项目路径数组
   */
  public static async findProjectPaths(rootPath: string, options: ProjectScanOptions = {depth: 2}): Promise<string[]> {
    const patterns = []
    if (options && options.projectTypes) {
      for (let type in options.projectTypes) {
        const mainFiles = options.projectTypes[type].mains;
        if (mainFiles) {
          patterns.push(...mainFiles.map(file => {
            if (file.startsWith('.')) {
              return `**/*${file}`;
            }
            return `**/${file}`;
          }));
        }
      }
    }

    // 收集所有可能的项目路径
    const paths = await FileUtil.findPaths(rootPath, {
      depth: options.depth,
      excludes: options.excludes,
      patterns
    });
    // 最后返回所有项目的文件夹
    return paths.map(s => path.dirname(s));
  }

  /**
   * 获取项目信息
   * @param projectPath 项目路径
   * @returns 项目信息
   */
  public static async getProjectSimpleInfo(projectPath: string): Promise<ProjectSimpleInfo | null> {
    const projectType = await ProjectClass.detectProjectType(projectPath);
    if (projectType.type === UNKNOWN_PROJECT_TYPE) {
      return null;
    }

    const colors: ColorSeries = ColorUtil.getColorSeries(projectType.color || '#0958d9');

    // 基本项目信息
    return {
      type: projectType.type,
      icon: projectType.icon,
      path: projectPath,
      name: path.basename(projectPath),
      colors
    };
  }

  /**
   * 获取项目详情
   * @param projectPath 项目路径
   */
  public static async getProjectDetail(projectPath: string): Promise<ProjectInfo | undefined> {
    if (!this.detailMap.has(projectPath)) {
      // 如果没有缓存则重新获取
      const simpleInfo = this.simpleMap.get(projectPath);
      if (!simpleInfo) {
        return undefined;
      }
      const projectTypes = globalConfig.config.scan.projectTypes;
      const projectTypeOption = projectTypes[simpleInfo.type];
      if (!projectTypeOption) {
        return undefined;
      }
      if (projectTypeOption.scanner) {
        const scannerResult = await projectTypeOption.scanner(projectPath);
        if (!scannerResult) {
          return undefined;
        }
        this.detailMap.set(projectPath, {
          ...simpleInfo,
          ...scannerResult
        });
      }
    }
    // 从缓存获取返回
    return this.detailMap.get(projectPath);
  }

  /**
   * 清除项目详情缓存
   */
  public static clearDetailMap() {
    this.detailMap.clear();
  }

  /**
   * 构建项目树
   * @param projects 项目列表
   * @returns 项目树结构
   */
  public static buildProjectTree(projects: ProjectSimpleInfo[]): ProjectSimpleTree[] {
    // 复制项目列表，避免修改原始数据
    const projectsCopy = JsonUtil.deepClone(projects);

    // 按路径长度排序项目，确保父项目先于子项目处理
    const sortedProjects = projectsCopy.sort((a, b) => a.path.length - b.path.length);

    // 创建项目路径到项目的映射
    const projectMap = new Map<string, ProjectSimpleTree>();

    // 将所有项目转换为树节点并放入映射中
    sortedProjects.forEach(project => {
      const treeNode: ProjectSimpleTree = {
        ...project,
        children: []
      };
      projectMap.set(project.path, treeNode);
    });

    // 用于存储根项目
    const rootProjects: ProjectSimpleTree[] = [];

    // 建立项目之间的父子关系
    for (const project of sortedProjects) {
      const currentNode = projectMap.get(project.path);
      if (!currentNode) continue;

      // 尝试查找父项目
      let isRoot = true;

      for (const potentialParent of sortedProjects) {
        // 跳过自身
        if (project.path === potentialParent.path) {
          continue;
        }

        // 如果当前项目路径是潜在父项目路径的子路径
        if (project.path.startsWith(potentialParent.path + path.sep)) {
          isRoot = false;
          const parentNode = projectMap.get(potentialParent.path);

          if (parentNode) {
            // 将当前项目添加为父项目的子项目
            parentNode.children?.push(currentNode);

            // 找到最近的父项目后跳出循环
            break;
          }
        }
      }

      // 如果没有找到父项目，则该项目为根项目
      if (isRoot) {
        rootProjects.push(currentNode);
      }
    }

    return rootProjects;
  }
}
